Set TCR_EL1.EPD1 bit to 1
authorAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Fri, 15 Sep 2017 09:30:34 +0000 (10:30 +0100)
committerAntonio Nino Diaz <antonio.ninodiaz@arm.com>
Thu, 21 Sep 2017 10:57:11 +0000 (11:57 +0100)
In the S-EL1&0 translation regime we aren't using the higher VA range,
whose translation table base address is held in TTBR1_EL1. The bit
TCR_EL1.EPD1 can be used to disable translations using TTBR1_EL1, but
the code wasn't setting it to 1. Additionally, other fields in TCR1_EL1
associated with the higher VA range (TBI1, TG1, SH1, ORGN1, IRGN1 and
A1) weren't set correctly as they were left as 0. In particular, 0 is a
reserved value for TG1. Also, TBBR1_EL1 was not explicitly set and its
reset value is UNKNOWN.

Therefore memory accesses to the higher VA range would result in
unpredictable behaviour as a translation table walk would be attempted
using an UNKNOWN value in TTBR1_EL1.

On the FVP and Juno platforms accessing the higher VA range resulted in
a translation fault, but this may not always be the case on all
platforms.

This patch sets the bit TCR_EL1.EPD1 to 1 so that any kind of
unpredictable behaviour is prevented.

This bug only affects the AArch64 version of the code, the AArch32
version sets this bit to 1 as expected.

Change-Id: I481c000deda5bc33a475631301767b9e0474a303
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
include/lib/aarch64/arch.h
lib/xlat_tables/aarch64/xlat_tables.c
lib/xlat_tables_v2/aarch64/xlat_tables_arch.c

index e38a53075b398ba28d03115e75d5944c0d803c38..188b0b75a046af37972d9ea110accc342019ffcb 100644 (file)
 #define TCR_SH_OUTER_SHAREABLE (U(0x2) << 12)
 #define TCR_SH_INNER_SHAREABLE (U(0x3) << 12)
 
+#define TCR_EPD1_BIT           (U(1) << 23)
+
 #define MODE_SP_SHIFT          U(0x0)
 #define MODE_SP_MASK           U(0x1)
 #define MODE_SP_EL0            U(0x0)
index 2ddf8cba8e4226899a21bfcac9f03fe292dda885..28ae1f73becff92d6d40b5a1a536823baed75866 100644 (file)
@@ -182,7 +182,11 @@ void init_xlat_tables(void)
 
 /* Define EL1 and EL3 variants of the function enabling the MMU */
 DEFINE_ENABLE_MMU_EL(1,
-               (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
+               /*
+                * TCR_EL1.EPD1: Disable translation table walk for addresses
+                * that are translated using TTBR1_EL1.
+                */
+               TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT),
                tlbivmalle1)
 DEFINE_ENABLE_MMU_EL(3,
                TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT),
index 097e815ccbd1dac70a6621697e73d033818b2495..760db928b447a4989e7f7adb9fe479c067179e0d 100644 (file)
@@ -256,7 +256,11 @@ void enable_mmu_arch(unsigned int flags,
 
 #if IMAGE_EL == 1
        assert(IS_IN_EL(1));
-       tcr |= tcr_ps_bits << TCR_EL1_IPS_SHIFT;
+       /*
+        * TCR_EL1.EPD1: Disable translation table walk for addresses that are
+        * translated using TTBR1_EL1.
+        */
+       tcr |= TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT);
        enable_mmu_internal_el1(flags, mair, tcr, ttbr);
 #elif IMAGE_EL == 3
        assert(IS_IN_EL(3));